<?php

/**
 * @author Ianaré Sévi
 * @author Dariusz Górecki <darek.krk@gmail.com>
 * @author Invenzzia Group, open-source division of CleverIT company http://www.invenzzia.org
 * @copyright 2011 CleverIT http://www.cleverit.com.pl
 * @license New BSD license
 * @version 1.3
 * @category ext
 * @package ext.YiiMongoDbSuite
 */

/**
 * @since v1.2.2
 */
class MongoCRUDCode extends CCodeModel
{
	public $model;
	public $controller;
	public $baseControllerClass = 'Controller';
	private $_modelClass;
	private $_modelObject;

	public function rules()
	{
		return array_merge(parent::rules(), array(
					array('model, controller', 'filter', 'filter' => 'trim'),
					array('model, controller, baseControllerClass', 'required'),
					array('model', 'match', 'pattern' => '/^\w+[\w+\\.]*$/', 'message' => '{attribute} should only contain word characters and dots.'),
					array('controller', 'match', 'pattern' => '/^\w+[\w+\\/]*$/', 'message' => '{attribute} should only contain word characters and slashes.'),
					array('baseControllerClass', 'match', 'pattern' => '/^[a-zA-Z_]\w*$/', 'message' => '{attribute} should only contain word characters.'),
					array('baseControllerClass', 'validateReservedWord', 'skipOnError' => true),
					array('model', 'validateModel'),
					array('baseControllerClass', 'sticky'),
				));
	}

	public function requiredTemplates()
	{
		return array(
			'controller.php',
		);
	}

	public function attributeLabels()
	{
		return array_merge(parent::attributeLabels(), array(
					'model' => 'Model Class',
					'controller' => 'Controller ID',
					'baseControllerClass' => 'Base Controller Class',
				));
	}

	public function successMessage()
	{
		$link = CHtml::link('try it now', Yii::app()->createUrl($this->controller), array('target' => '_blank'));
		return "The controller has been generated successfully. You may $link.";
	}

	public function validateModel($attribute, $params)
	{
		if ($this->hasErrors('model'))
			return;
		$class = @Yii::import($this->model, true);
		if (!is_string($class) || !$this->classExists($class))
			$this->addError('model', "Class '{$this->model}' does not exist or has syntax error.");
		else if (!is_subclass_of($class, 'EMongoDocument'))
			$this->addError('model', "'{$this->model}' must extend from EMongoDocument.");
		else
		{
			$this->_modelClass = $class;
			$this->_modelObject = call_user_func($class . '::model');
		}
	}

	public function prepare()
	{
		$this->files = array();
		$templatePath = $this->templatePath;
		$controllerTemplateFile = $templatePath . DIRECTORY_SEPARATOR . 'controller.php';

		$this->files[] = new CCodeFile(
						$this->controllerFile,
						$this->render($controllerTemplateFile, array('this' => $this))
		);

		$files = scandir($templatePath);
		foreach ($files as $file)
		{
			if (is_file($templatePath . '/' . $file) && CFileHelper::getExtension($file) === 'php' && $file !== 'controller.php')
			{
				$this->files[] = new CCodeFile(
								$this->viewPath . DIRECTORY_SEPARATOR . $file,
								$this->render($templatePath . '/' . $file, array('this' => $this))
				);
			}
		}
	}

	public function getModelClass()
	{
		return $this->_modelClass;
	}

	public function getModelObject()
	{
		return $this->_modelObject;
	}

	public function getControllerClass()
	{
		if (($pos = strrpos($this->controller, '/')) !== false)
			return ucfirst(substr($this->controller, $pos + 1)) . 'Controller';
		else
			return ucfirst($this->controller) . 'Controller';
	}

	public function getModule()
	{
		if (($pos = strpos($this->controller, '/')) !== false)
		{
			$id = substr($this->controller, 0, $pos);
			if (($module = Yii::app()->getModule($id)) !== null)
				return $module;
		}
		return Yii::app();
	}

	public function getControllerID()
	{
		if ($this->getModule() !== Yii::app())
			$id = substr($this->controller, strpos($this->controller, '/') + 1);
		else
			$id = $this->controller;
		if (($pos = strrpos($id, '/')) !== false)
			$id[$pos + 1] = strtolower($id[$pos + 1]);
		else
			$id[0] = strtolower($id[0]);
		return $id;
	}

	public function getUniqueControllerID()
	{
		$id = $this->controller;
		if (($pos = strrpos($id, '/')) !== false)
			$id[$pos + 1] = strtolower($id[$pos + 1]);
		else
			$id[0] = strtolower($id[0]);
		return $id;
	}

	public function getControllerFile()
	{
		$module = $this->getModule();
		$id = $this->getControllerID();
		if (($pos = strrpos($id, '/')) !== false)
			$id[$pos + 1] = strtoupper($id[$pos + 1]);
		else
			$id[0] = strtoupper($id[0]);
		return $module->getControllerPath() . '/' . $id . 'Controller.php';
	}

	public function getViewPath()
	{
		return $this->getModule()->getViewPath() . '/' . $this->getControllerID();
	}

	public function generateActiveLabel($modelClass, $name)
	{
		return "\$form->labelEx(\$model,'{$name}')";
	}

	public function generateActiveField($modelClass, $name)
	{
		return "\$form->textField(\$model,'{$name}')";
	}

	/**
	 * @since v1.2.3
	 */
	public function generateInputField($modelClass, $name)
	{
		return "CHtml::activeTextField(\$model,'{$name}')";
	}

	public function guessNameColumn(EMongoDocument $model)
	{
		foreach ($model->attributeNames() as $name)
		{
			if (!strcasecmp($name, 'name'))
				return $name;
		}
		foreach ($model->attributeNames() as $name)
		{
			if (!strcasecmp($name, 'title'))
				return $name;
		}
		foreach ($model->attributeNames() as $name)
		{
			if ($name == $model->primaryKey())
				return $name;
		}
		return '_id';
	}

}